/**********************************************************************
 *** *                                                            * ***
 *** *  Copyright (c) 2013 Harmonia Holdings Group LLC            * ***
 *** *                                                            * ***
 *** * Permission is hereby granted to use, modify, copy, and     * ***
 *** * distribute this software and its documentation for any     * ***
 *** * purpose only without profit, provided that the above       * ***
 *** * Copyright Notice appears in all copies and that both the   * ***
 *** * Copyright Notice and this Permission Notice appears in     * ***
 *** * every copy of supporting documentation.  No title to nor   * ***
 *** * ownership of the software is transferred hereby.  The name * ***
 *** * of Harmonia Holdings Group LLC shall not be used in        * ***
 *** * advertising or publicity related to the distribution of    * ***
 *** * the software without specific, written, prior permission.  * ***
 *** * This software is provided as-delivered without expressed   * ***
 *** * or implied warranty.  Harmonia Holdings Group LLC          * ***
 *** * makes no representation about the suitability of this      * ***
 *** * software for any purpose and accepts no responsibility for * ***
 *** * its use.                                                   * ***
 *** *                                                            * ***
 *** ************************************************************** ***
 *** *                                                            * ***
 *** * This program is free software; you can redistribute it     * ***
 *** * and/or modify it under the terms of the GNU General Public * ***
 *** * License as published by the Free Software Foundation;      * ***
 *** * either version 2 of the License, or (at your option) any   * ***
 *** * later version.                                             * ***
 *** *                                                            * ***
 *** * This program is distributed in the hope that it will be    * ***
 *** * useful, but WITHOUT ANY WARRANTY; without even the implied * ***
 *** * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR    * ***
 *** * PURPOSE.  See the GNU General Public License for more      * ***
 *** * details.                                                   * ***
 *** *                                                            * ***
 *** * You should have received a copy of the GNU General Public  * ***
 *** * License along with this program; if not, write to the Free * ***
 *** * Software Foundation, Inc., 51 Franklin Street, Fifth       * ***
 *** * Floor, Boston, MA 02110-1301, USA.                         * ***
 *** *                                                            * ***
 *** * For more information: http://www.gnu.org/licenses/gpl.html * ***
 *** *                                                            * ***
 **********************************************************************/
package org.etexascode.interrep.datamodel;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.etexascode.interrep.datamodel.utils.UtilsStringOnModel;
/**
 * The lane manager model.
 * @author jrutherford
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(value = Lane.class)
@XmlRootElement(name="LaneManager")
public class LaneManager implements Serializable {
	/** Serial ID. */
	@XmlTransient
	private static final long serialVersionUID = 7163537396158539634L;

	/** The latitude. */
	@XmlElement
	private double latitude;

	/** The longitude. */
	@XmlElement
	private double longitude;

	/** The elevation. */
	@XmlElement
	private double elevation;

	/** The map of lanes. */
	@XmlElement
	@XmlJavaTypeAdapter(ManagerAdapter.class)
	private Map<Integer, Lane> lanes;
	
	/** The id of the this intersections */
	@XmlElement
	private int intersectionId;

	/**
	 * The calculator type to be used in lat,long conversions. (Calculator type is used by UtilsLatLongConversions for calculations)
	 */
	@XmlElement
	private int geoCalculatorType = 1;

	/** Constructor. */
	public LaneManager() {
		latitude = 0.0;
		longitude = 0.0;
		elevation = 0.0;
		lanes = new HashMap<Integer, Lane>();
		intersectionId = 0;
	}

	/** Check if 2 lane managers are equal. */
	@Override
	public boolean equals(Object obj) {
		if(obj instanceof LaneManager) {
			LaneManager lm = (LaneManager) obj;

			if(Double.compare(latitude,lm.latitude) != 0) {
				return false;
			}

			if(Double.compare(longitude, lm.longitude) != 0) {
				return false;
			}

			if(Double.compare(elevation, lm.elevation) != 0) {
				return false;
			}
			Set<Integer> thisKeys = lanes.keySet();
			Set<Integer> lmKeys = lm.lanes.keySet();

			if(!(thisKeys.containsAll(lmKeys) && lmKeys.containsAll(thisKeys))) {
				return false;
			}

			for(Integer i:lmKeys) {

				if(!lm.lanes.get(i).equals(lanes.get(i))) {
					return false;
				}
			}

			return true;
		}
		return false;
	}

	/**
	 * HashCode operation. 
	 * @return A hashcode of the data. 
	 */
	@Override
	public int hashCode() {
		return new HashCodeBuilder(45, 23).
				append(latitude).
				append(longitude).
				append(elevation).
				toHashCode();
	}

	/**
	 * Gets the elevation.
	 * @return The elevation.
	 */
	public double getElevation() {
		return elevation;
	}


	/**
	 * Gets the lane by ID.
	 * @param id The ID.
	 * @return The lane.
	 */
	public Lane getLaneById(int id) {
		return lanes.get(id);
	}

	/**
	 * Gets the map of lanes.
	 * @return The map of lanes.
	 */
	public Map<Integer, Lane> getLanes() {
		return lanes;
	}

	/**
	 * Gets the latitude.
	 * @return The latitude.
	 */
	public double getLatitude() {
		return latitude;
	}

	/**
	 * Gets the longitude.
	 * @return The longitude.
	 */
	public double getLongitude() {
		return longitude;
	}

	/**
	 * Sets the elevation.
	 * @param elevation The new elevation.
	 */
	public void setElevation(double elevation) {
		this.elevation = elevation;
	}

	/**
	 * Sets the map of lanes.
	 * @param lanes The new lanes.
	 */
	public void setLanes(Map<Integer, Lane> lanes) {
		this.lanes = lanes;
	}

	/**
	 * Sets the latitude.
	 * @param latitude The latitude.
	 */
	public void setLatitude(double latitude) {
		this.latitude = latitude;
	}

	/**
	 * Sets the longitude.
	 * @param longitude The longitude.
	 */
	public void setLongitude(double longitude) {
		this.longitude = longitude;
	}

	/**
	 * Get the type of Calculator being used by the simulation.
	 * 
	 * @return the type of Calculator
	 */
	public int getGeoCalculatorType() {
		return geoCalculatorType;
	}

	/**
	 * Set the type of Calculator being used by the simulation.
	 * 
	 * @param geoCalculatorType
	 */
	public void setGeoCalculatorType(int geoCalculatorType) {
		this.geoCalculatorType = geoCalculatorType;
	}

	/** String representation. */
	@Override
	public String toString() {
		StringBuilder ret = new StringBuilder();

		UtilsStringOnModel.addDouble(ret, latitude, "latitude");
		UtilsStringOnModel.addDouble(ret, longitude, "longitude");
		UtilsStringOnModel.addDouble(ret, elevation, "elevation");
		UtilsStringOnModel.addMap(ret, lanes, "lanes");

		return ret.toString();
	}

	/**
	 * Getter.
	 * @return Get the id of the intersection.
	 */
	public int getIntersectionId() {
		return intersectionId;
	}

	/**
	 * Setter.
	 * @param intersectionId The new intersection id.
	 */
	public void setIntersectionId(int intersectionId) {
		this.intersectionId = intersectionId;
	}
}